<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2019/5/10
 * Time: 9:48
 */

namespace Game\Models\Common;
use Game\Lib\RedisConst;
use Game\Module\Redis;
use Game\Lib\GlobalConst;
use Game\Lib\Game;
use Predis\Client;

trait RedisData
{


    /**
     * 获取房间玩法设置
     * @param $room_id
     * @param bool $field;
     * @return mixed
     */
    protected function queryRoomKey($room_id,$field=false){
        $roomKey = strtr(RedisConst::Room_Key, array("[roomid]"=>$room_id));
        if ($field) {
            return Redis::getInstance()->hget($roomKey,$field);
        }else {
            return Redis::getInstance()->hgetall($roomKey);
        }
    }
    protected function updateRoomKey($room_id, $data){
        $roomKey = strtr(RedisConst::Room_Key, array("[roomid]"=>$room_id));
        return Redis::getInstance()->hmset($roomKey,$data);
    }
    protected function hincrbyRoomKey($room_id, $field, $increment){
        $roomKey = strtr(RedisConst::Room_Key, array("[roomid]"=>$room_id));
        return Redis::getInstance()->hincrby($roomKey, $field, $increment);
    }
    protected function deleteRoomKey($room_id){
        $roomKey = strtr(RedisConst::Room_Key, array("[roomid]"=>$room_id));
        return Redis::getInstance()->del([$roomKey]);
    }
    /**
     * 查询Card_Key
     * @param $room_id
     * @param bool $field
     * @return array|string
     */
    protected function queryCardKey($room_id,$field=false){
        $cardKey = strtr(RedisConst::Card_Key, array("[roomid]"=>$room_id));
        if ($field) {
            return Redis::getInstance()->hget($cardKey,$field);
        }else {
            return Redis::getInstance()->hgetall($cardKey);
        }
    }
    protected function updateCardKey($room_id, $data){
        $cardKey = strtr(RedisConst::Card_Key, array("[roomid]"=>$room_id));
        return Redis::getInstance()->hmset($cardKey,$data);
    }
    protected function deleteCardKey($room_id){
        $cardKey = strtr(RedisConst::Card_Key, array("[roomid]"=>$room_id));
        return Redis::getInstance()->del([$cardKey]);
    }
    /**
     * 查询Play_Key
     * @param $room_id
     * @param bool $field
     * @return array|string
     */
    protected function queryPlayKey($room_id,$field=false){
        $playKey = strtr(RedisConst::Play_Key, array("[roomid]"=>$room_id));
        if ($field) {
            return Redis::getInstance()->hget($playKey,$field);
        }else {
            return Redis::getInstance()->hgetall($playKey);
        }
    }
    protected function hincrbyPlayKey($room_id, $field, $increment){
        $playKey = strtr(RedisConst::Play_Key, array("[roomid]"=>$room_id));
        return Redis::getInstance()->hincrby($playKey,$field,$increment);
    }
    protected function updatePlayKey($room_id, $data){
        $playKey = strtr(RedisConst::Play_Key, array("[roomid]"=>$room_id));
        return Redis::getInstance()->hmset($playKey,$data);
    }
    protected function deletePlayKey($room_id){
        $playKey = strtr(RedisConst::Play_Key, array("[roomid]"=>$room_id));
        return Redis::getInstance()->del([$playKey]);
    }

    /**
     * 查询Chip_Key
     * @param $room_id
     * @param bool $account_id
     * @return array|string
     */
    protected function queryChipKey($room_id,$account_id=false){
        $chipKey = strtr(RedisConst::Chip_Key, array("[roomid]"=>$room_id));
        if ($account_id) {
            return Redis::getInstance()->hget($chipKey,$account_id);
        }else {
            return Redis::getInstance()->hgetall($chipKey);
        }
    }
    protected function hincrbyChipKey($room_id, $account_id, $score){
        $chipKey = strtr(RedisConst::Chip_Key, array("[roomid]"=>$room_id));
        return Redis::getInstance()->hincrby($chipKey, $account_id, $score);
    }
    protected function updateChipKey($room_id, $data){
        $chipKey = strtr(RedisConst::Chip_Key, array("[roomid]"=>$room_id));
        return Redis::getInstance()->hmset($chipKey,$data);
    }
    protected function deleteChipKey($room_id){
        $chipKey = strtr(RedisConst::Chip_Key, array("[roomid]"=>$room_id));
        return Redis::getInstance()->del([$chipKey]);
    }

    /**
     * 查询Chip_Key
     * @param $room_id
     * @param bool $field
     * @return array|string
     */
    protected function querySeenCardKey($room_id,$field=false){
        $seenCardKey = strtr(RedisConst::SeenCard_Key, array("[roomid]"=>$room_id));
        if ($field) {
            return Redis::getInstance()->hget($seenCardKey,$field);
        }else {
            return Redis::getInstance()->hgetall($seenCardKey);
        }
    }

    protected function updateSeenCardKey($room_id, $data){
        $seenCardKey = strtr(RedisConst::SeenCard_Key, array("[roomid]"=>$room_id));
        return Redis::getInstance()->hmset($seenCardKey,$data);
    }
    protected function deleteSeenCardKey($room_id){
        $seenCardKey = strtr(RedisConst::SeenCard_Key, array("[roomid]"=>$room_id));
        return Redis::getInstance()->del([$seenCardKey]);
    }
    /**
     * 查询AccountStatus_Key
     * @param $room_id
     * @param bool $field
     * @return array|string
     */
    protected function queryAccountStatusKey($room_id,$field=false){
        $accountStatusKey = strtr(RedisConst::AccountStatus_Key, array("[roomid]"=>$room_id));
        if ($field) {
            return Redis::getInstance()->hget($accountStatusKey,$field);
        }else {
            return Redis::getInstance()->hgetall($accountStatusKey);
        }
    }

    protected function updateAccountStatusKey($room_id, $data){
        $accountStatusKey = strtr(RedisConst::AccountStatus_Key, array("[roomid]"=>$room_id));
        return Redis::getInstance()->hmset($accountStatusKey,$data);
    }

    protected function deleteAccountStatusKey($room_id){
        $accountStatusKey = strtr(RedisConst::AccountStatus_Key, array("[roomid]"=>$room_id));
        return Redis::getInstance()->del([$accountStatusKey]);
    }
    /**
     * 查询RoomScore_Key
     * @param $room_id
     * @param bool $account_id
     * @return array|string
     */
    protected function queryRoomScoreKey($room_id, $account_id=false){
        $roomScoreKey = strtr(RedisConst::RoomScore_Key, array("[roomid]"=>$room_id));
        if ($account_id) {
            return Redis::getInstance()->hget($roomScoreKey,$account_id);
        }else {
            return Redis::getInstance()->hgetall($roomScoreKey);
        }
    }
    protected function hincrbyRoomScoreKey($room_id, $account_id, $score){
        $roomScoreKey = strtr(RedisConst::RoomScore_Key, array("[roomid]"=>$room_id));
        return Redis::getInstance()->hincrby($roomScoreKey,$account_id,$score);
    }
    protected function updateRoomScoreKey($room_id, $data){
        $roomScoreKey = strtr(RedisConst::RoomScore_Key, array("[roomid]"=>$room_id));
        return Redis::getInstance()->hmset($roomScoreKey,$data);
    }
    protected function deleteRoomScoreKey($room_id){
        $roomScoreKey = strtr(RedisConst::RoomScore_Key, array("[roomid]"=>$room_id));
        return Redis::getInstance()->del([$roomScoreKey]);
    }


    //获取房间状态
    protected function queryRoomStatus($room_id){
        return $this->queryRoomKey($room_id,RedisConst::Room_Field_Status);
    }

    //获取房间每轮需要消耗的房卡数
    protected function queryTicketCount($room_id){
        $result = $this->queryRoomKey($room_id,RedisConst::Room_Field_TicketCount);
        return $result > 0 ? $result : 1;
    }

    //获取房间一轮总局数
//    protected function queryTotalNum($room_id){
//        return $this->queryRoomKey($room_id,RedisConst::Room_Field_TotalNum);
//    }
//
    //获取房间当前局数
//    protected function queryGameNumber($room_id){
//        return $this->queryRoomKey($room_id,RedisConst::Room_Field_GameNum);
//    }


    //返回积分榜
    protected function queryScoreboard($room_id){
        $result = $this->queryRoomKey($room_id,RedisConst::Room_Field_Scoreboard);
        if($result !== RedisConst::DATA_NONEXISTENT){
            $arr = json_decode($result);
        } else {
            $arr = new \stdClass();
        }
        return $arr;
    }


    //获取房间积分榜 json string
    protected function queryRoomScoreboard($room_id){
        return  $this->queryRoomKey($room_id,RedisConst::Room_Field_Scoreboard);
    }


    //获取叫分基准
    protected function queryBenchmark($room_id){
        return $this->queryPlayKey($room_id,RedisConst::Play_Field_Benchmark);
    }
    //设置叫分基准
    protected function updateBenchmark($room_id, $benchmark){
        if($benchmark < 0){
            return false;
        }
        $mkv[RedisConst::Play_Field_Benchmark] = $benchmark;
        return $this->updatePlayKey($room_id, $mkv);
    }

    //获取分数池分数
    protected function queryPoolScore($room_id){
        $result = $this->queryPlayKey($room_id,RedisConst::Play_Field_PoolScore);
        return $result > 0 ? $result : 0;
    }

    //获取庄家account_id
    protected function queryBanker($room_id){
        $result = $this->queryRoomKey($room_id,RedisConst::Room_Field_Banker);
        return $result > 0 ? $result : -1;
    }
    //获取房主id
    protected function queryCreator($room_id){
        $result = $this->queryRoomKey($room_id,RedisConst::Room_Field_Creator);
        return $result;
    }

    //获取激活的操作中的用户
    protected function queryActiveUser($room_id){
        $result = $this->queryPlayKey($room_id,RedisConst::Play_Field_ActiveUser);
        return  $result > 0 ? $result : -1;
    }

    //获取开局时间
    protected function queryStartTime($room_id){
        $result = $this->queryRoomKey($room_id,RedisConst::Room_Field_StartTime);
        return  $result > 0 ? $result : -1;
    }
    //更新游戏开局时间
    protected function updateStartTime($room_id){
        $mkv[RedisConst::Room_Field_StartTime] = time();
        return $this->updateRoomKey($room_id,$mkv);
    }

    /**
     * RoomScore_Key
     * @param $room_id
     * @param $mkv
     * @param int $is_rpush
     * @param int $is_pushx
     */
    protected function pushPlayMemberKeyList($room_id,$mkv,$is_rpush=GlobalConst::IS_TRUE, $is_pushx=GlobalConst::IS_TRUE){
        $playMemberKey = strtr(RedisConst::PlayerMember_Key, array("[roomid]"=>$room_id));
        foreach($mkv as $value) {
            if(trim($value) === GlobalConst::EMPTY_STRING) {
                continue;
            }
            if($is_pushx == GlobalConst::IS_TRUE) {
                if($is_rpush == GlobalConst::IS_TRUE) {
                    Redis::getInstance()->rpushx($playMemberKey,$value) ;  //在(已存在)队列右方插入值
                } else {
                    Redis::getInstance()->lpushx($playMemberKey,$value) ;  //在(已存在)队列左方插入值
                }
            } else {
                if($is_rpush == GlobalConst::IS_TRUE) {
                    Redis::getInstance()->rpush($playMemberKey,$value) ;  //在(不存在则新建)列右方插入值
                } else {
                    Redis::getInstance()->lpush($playMemberKey,$value) ;  //在(不存在则新建)队列左方插入值
                }
            }
        }
    }

    protected function rpoplpushPlayMemberKey($room_id){
        $playMemberKey = strtr(RedisConst::PlayerMember_Key, array("[roomid]"=>$room_id));
        return Redis::getInstance()->rpoplpush($playMemberKey,$playMemberKey);
    }

    protected function lrangePlayMemberKey($room_id,$start = 0, $stop = -1){
        $playMemberKey = strtr(RedisConst::PlayerMember_Key, array("[roomid]"=>$room_id));
        return Redis::getInstance()->lrange($playMemberKey, $start, $stop);
    }
    protected function llenPlayMemberKey($room_id){
        $playMemberKey = strtr(RedisConst::PlayerMember_Key, array("[roomid]"=>$room_id));
        return Redis::getInstance()->llen($playMemberKey);
    }
    protected function lremPlayMemberKey($room_id, $count, $account_id){
        $playMemberKey = strtr(RedisConst::PlayerMember_Key, array("[roomid]"=>$room_id));
        return Redis::getInstance()->lrem($playMemberKey,$count,$account_id);
    }

    protected function deletePlayMemberKey($room_id){
        $playMemberKey = strtr(RedisConst::PlayerMember_Key, array("[roomid]"=>$room_id));
        return Redis::getInstance()->del([$playMemberKey]);
    }

    /**
     * RoomScore_Key
     * @param $room_id
     * @param $mkv
     * @param int $is_rpush
     * @param int $is_pushx
     */
    protected function pushRoomGuestKeyList($room_id,$mkv,$is_rpush=GlobalConst::IS_TRUE, $is_pushx=GlobalConst::IS_TRUE){
        $roomGuestKey = strtr(RedisConst::RoomGuest_Key, array("[roomid]"=>$room_id));
        foreach($mkv as $value) {
            if(trim($value) === GlobalConst::EMPTY_STRING) {
                continue;
            }
            if($is_pushx == GlobalConst::IS_TRUE) {
                if($is_rpush == GlobalConst::IS_TRUE) {
                    Redis::getInstance()->rpushx($roomGuestKey,$value) ;  //在(已存在)队列右方插入值
                } else {
                    Redis::getInstance()->lpushx($roomGuestKey,$value) ;  //在(已存在)队列左方插入值
                }
            } else {
                if($is_rpush == GlobalConst::IS_TRUE) {
                    Redis::getInstance()->rpush($roomGuestKey,$value) ;  //在(不存在则新建)列右方插入值
                } else {
                    Redis::getInstance()->lpush($roomGuestKey,$value) ;  //在(不存在则新建)队列左方插入值
                }
            }
        }
    }

    protected function lrangeRoomGuestKey($room_id, $start = 0, $stop = -1){
        $roomGuestKey = strtr(RedisConst::RoomGuest_Key, array("[roomid]"=>$room_id));
        return Redis::getInstance()->lrange($roomGuestKey, $start, $stop);
    }

    protected function deleteRoomGuestKey($room_id){
        $roomGuestKey = strtr(RedisConst::RoomGuest_Key, array("[roomid]"=>$room_id));
        return Redis::getInstance()->del([$roomGuestKey]);
    }
    protected function lremRoomGuestKey($room_id,$count,$account_id){
        $roomGuestKey = strtr(RedisConst::RoomGuest_Key, array("[roomid]"=>$room_id));
        return Redis::getInstance()->lrem($roomGuestKey,$count,$account_id);
    }
    protected function llenRoomGuestKey($room_id){
        $roomGuestKey = strtr(RedisConst::RoomGuest_Key, array("[roomid]"=>$room_id));
        return Redis::getInstance()->llen($roomGuestKey);
    }
    /**
     * 查询倒计时
     * @param $room_id
     * @param $limit
     * @return bool|int|string
     */
    protected function queryCountdown($room_id, $limit){
        $timer_time = $this->queryPlayKey($room_id,RedisConst::Play_Field_TimerTime);
        if($timer_time > 0){
            $countdown = $limit - time() + $timer_time;
            return $countdown > 0 ? $countdown : 0;
        } else {
            return 0;
        }
    }


    /**
     * 设置或取消(timer_id  -1)定时器
     * @param $room_id
     * @param $timer_id
     * @return mixed
     */
    protected function updateTimer($room_id, $timer_id){
        $mkv[RedisConst::Play_Field_TimerId] = $timer_id;
        if($timer_id > 0){
            $mkv[RedisConst::Play_Field_TimerTime] = time();
        } else {
            $mkv[RedisConst::Play_Field_TimerTime] = -1;
        }
        return $this->updatePlayKey($room_id,$mkv);
    }

    protected function setTimerId($room_id, $timer_id){
        $mkv[RedisConst::Play_Field_TimerId] = $timer_id;
        return $this->updatePlayKey($room_id,$mkv);
    }
    protected function setTimerTime($room_id){
        $mkv[RedisConst::Play_Field_TimerTime] = time();
        return $this->updatePlayKey($room_id,$mkv);
    }
    protected function getTimerTime($room_id){
        $result = $this->queryPlayKey($room_id, RedisConst::Play_Field_TimerTime);
        return $result > 0 ? $result : -1;
    }

    /**
     * 获取定时器id
     * @param $room_id
     * @return array|int|string
     */
    protected function queryTimerId($room_id){
        $result = $this->queryPlayKey($room_id, RedisConst::Play_Field_TimerId);
        return $result > 0 ? $result : -1;
    }

    /**
     * 更新房间状态
     * @param $room_id
     * @param $status
     * @return mixed
     */
    protected function updateRoomStatus($room_id, $status){
        $mkv[RedisConst::Room_Field_Status] = $status;
        return $this->updateRoomKey($room_id,$mkv);
    }

    /**
     * 获取游戏中的人数
     * @param $room_id
     * @return int
     */
    protected function queryPlayMemberCount($room_id){
        return $this->llenPlayMemberKey($room_id);
    }

    /**
     * 获取用户状态
     * @param $room_id
     * @param $account_id
     * @return bool|string
     */
    protected function queryAccountStatus($room_id, $account_id){
        return $this->queryAccountStatusKey($room_id,$account_id);
    }


    /**
     * 重新设置所有用户状态为未准备
     * @param $room_id
     * @param int $reset_status
     */
    protected function resetAllAccountStatus($room_id, $reset_status=Game::AccountStatus_Notready){
        $mkv = array();
        $members = $this->queryRoomMembers($room_id);
        if(is_array($members) && count($members)){
            foreach ($members as $account_id) {
                $pre_status = $this->queryAccountStatus($room_id, $account_id);
                $status = ($pre_status == Game::AccountStatus_Initial) ? Game::AccountStatus_Initial : $reset_status;

                $mkv[$account_id] = $status;
            }
        }
        $this->updateAccountStatusKey($room_id,$mkv);
    }

    /**
     * 重新设置所有用户分数为0
     * @param $room_id
     */
    protected function resetAllAccountScore($room_id){
        $mkv = array();
        $members = $this->queryRoomMembers($room_id);
        if(is_array($members) && count($members)){
            foreach ($members as $account_id) {
                $mkv[$account_id] = 0;
            }
        }
        $this->updateRoomScoreKey($room_id,$mkv);
    }


    /**
     * 获取房间用户
     * @param $room_id
     * @param bool $withscores
     * @return array
     */
    protected function queryRoomMembers($room_id, $withscores=false){
        $roomSequenceKey = strtr(RedisConst::RoomPlayerSequence_Key, array("[roomid]"=>$room_id));
        if ($withscores){
            $result = Redis::getInstance()->zrange($roomSequenceKey,0,-1,array('WITHSCORES' => true));
        }else{
            $result = Redis::getInstance()->zrange($roomSequenceKey,0,-1);
        }

        $members = array();
        if(is_array($result) ){
            if($withscores){
                foreach ($result as $account_id => $serial_num) {
                    if($account_id < 0){
                        $account_id = -$account_id;
                    }
                    $members[$account_id] = $serial_num;
                }
            } else {
                foreach ($result as $account_id) {
                    if($account_id < 0){
                        $account_id = -$account_id;
                    }
                    $members[] = $account_id;
                }
            }
            return $members;
        } else {
            return array();
        }
    }

    protected function deleteRoomSequenceKey($room_id){
        $roomSequenceKey = strtr(RedisConst::RoomPlayerSequence_Key, array("[roomid]"=>$room_id));
        Redis::getInstance()->del([$roomSequenceKey]);
    }


    /**
     * 获取玩家的座位号  从1开始，-1表示未入座
     * @param $room_id
     * @param $account_id
     * @return int|mixed
     */
    protected function querySeatNumber($room_id, $account_id){
        $roomSequenceKey = strtr(RedisConst::RoomPlayerSequence_Key, array("[roomid]"=>$room_id));
        $members = Redis::getInstance()->zrange($roomSequenceKey,0,-1, array('WITHSCORES' => true));

        if(!is_array($members)){
            return -1;
        }
        if(isset($members[$account_id])){
            return $members[$account_id];
        } else if(isset($members[-$account_id])){
            return $members[-$account_id];
        } else {
            return -1;
        }
    }


    //获取用户是否已经扣除房卡
    protected function queryTicketChecked($room_id, $account_id){
        $roomSequenceKey = strtr(RedisConst::RoomPlayerSequence_Key, array("[roomid]"=>$room_id));
        $result = Redis::getInstance()->zscore($roomSequenceKey,$account_id);

        if($result > 0){
            return 1;
        } else {
            return 0;
        }
    }

    //获取checked的人
    protected function queryTicketCheckedUser($room_id){
        $roomSequenceKey = strtr(RedisConst::RoomPlayerSequence_Key, array("[roomid]"=>$room_id));
        $result = Redis::getInstance()->zrange($roomSequenceKey, 0, -1);
        $user_array = array();
        if(RedisConst::DATA_NONEXISTENT !== $result){
            foreach ($result as $account_id) {
                if($account_id > 0){
                    $user_array[] = $account_id;
                }
            }
        }
        return $user_array;
    }


    protected function setHashTransaction($room_id){
        $key = strtr(RedisConst::Room_Key, array("[roomid]"=>$room_id));
        $success = false;
        $options = array(
            'cas'   => true,    // Initialize with support for CAS operations
            'watch' => $key,    // Key that needs to be WATCHed to detect changes
            'retry' => 3,       // Number of retries on aborted transactions, after
            // which the client bails out with an exception.
        );

        Redis::getInstance()->transaction($options, function (Client $tx) use ($key, &$success) {
            $room_status = $tx->hget($key, RedisConst::Room_Field_Status);
            if (isset($room_status) && $room_status == 1) {
                $tx->multi();   // With CAS, MULTI *must* be explicitly invoked.
                $tx->hmset($key, array(RedisConst::Room_Field_Status => 2));
                $success =  true;

            } else {
//                $this->writeLog("room_status != 1");
                $success =  false;
            }
        });
        return $success;
    }

    //设置房间状态   1等待中   2游戏中
    protected function setRoomStatusTransaction($room_id,$pre_status,$update_status){
        $key = strtr(RedisConst::Room_Key, array("[roomid]"=>$room_id));
        $success = false;
        $options = array(
            'cas'   => true,    // Initialize with support for CAS operations
            'watch' => $key,    // Key that needs to be WATCHed to detect changes
            'retry' => 3,       // Number of retries on aborted transactions, after
            // which the client bails out with an exception.
        );

        Redis::getInstance()->transaction($options, function (Client $tx) use ($key,$pre_status,$update_status, &$success) {
            $room_status = $tx->hget($key, RedisConst::Room_Field_Status);
            if (isset($room_status) && $room_status == $pre_status) {
                $tx->multi();   // With CAS, MULTI *must* be explicitly invoked.
                $tx->hmset($key, array(RedisConst::Room_Field_Status => $update_status));
                $success =  true;

            } else {
                //$this->logMessage('error', "function(setRoomStatusTransaction):room_status error ".$pre_status." in file".__FILE__." on Line ".__LINE__);
                $success =  false;
            }
        });
        return $success;
    }

    /**
     * 离开座位的加锁函数  (离线回调或观战方法调用)
     * @param $room_id
     * @param $account_id
     * @return int
     */
    protected function leaveSeatTransaction($room_id,$account_id){
        $key = strtr(RedisConst::RoomPlayerSequence_Key, array("[roomid]"=>$room_id));
        $success = 0;
        $options = array(
            'cas'   => true,    // Initialize with support for CAS operations
            'watch' => $key,    // Key that needs to be WATCHed to detect changes
            'retry' => 3,       // Number of retries on aborted transactions, after
            // which the client bails out with an exception.
        );
        Redis::getInstance()->transaction($options, function (Client $tx) use ($key,$account_id, &$success) {
            $result = $tx->zrange($key,0,-1, array('WITHSCORES' => true));
            if(is_array($result)) {
                if(isset($result[$account_id])){ //checked 离座
                    $success = 1;
                } else if(isset($result[-$account_id])){ //unchecked 离座
                    $tx->zrem($key, -$account_id);
                    $success = 2;
                }
            }
        });
        return $success;
    }

    /**
     * 开始一局时检票
     * @param $room_id
     * @param $ready_in_room_user
     * @return array
     */
    protected function ticketCheckTransaction($room_id, $ready_in_room_user){
        $ret_array = array();
        $key = strtr(RedisConst::RoomPlayerSequence_Key, array("[roomid]"=>$room_id));

        $options = array(
            'cas'   => true,    // Initialize with support for CAS operations
            'watch' => $key,    // Key that needs to be WATCHed to detect changes
            'retry' => 3,       // Number of retries on aborted transactions, after
            // which the client bails out with an exception.
        );
        Redis::getInstance()->transaction($options, function (Client $tx) use ($key, $ready_in_room_user, &$ret_array) {
            $result = $tx->zrange($key,0,-1,array('WITHSCORES' => true));
            if(is_array($result)) {
                $ret_array = array_keys($result);
                $unchecked_arr = array();
                foreach ($result as $account_id => $serial_num) {
                    if($account_id < 0 && in_array(-$account_id, $ready_in_room_user)){
                        $unchecked_arr[$account_id] = $serial_num;
                    }
                }
                if(count($unchecked_arr) > 0){
                    foreach ($unchecked_arr as $account_id => $serial_num) {
                        $tx->zadd($key, [$serial_num => -$account_id]);
                    }
                    $unchecked_account_id = array_keys($unchecked_arr);
                    foreach ($unchecked_account_id as $account_id) {
                        $tx->zrem($key, $account_id);
                    }
                    for ($i=0; $i < count($ret_array); $i++) {
                        if($ret_array[$i] < 0){
                            $ret_array[$i] = -$ret_array[$i];
                        }
                    }
                }
            }
        });
        $ret_array = array_intersect($ready_in_room_user, $ret_array);
        return $ret_array;
    }

    /**
     * 进房并发
     * @param $room_id
     * @param $account_id
     * @param $max_count
     * @return bool
     */
    protected function joinRoomTransaction($room_id,$account_id,$max_count){
        $key = strtr(RedisConst::RoomPlayerSequence_Key, array("[roomid]"=>$room_id));
        $success = false;
        $options = array(
            'cas'   => true,    // Initialize with support for CAS operations
            'watch' => $key,    // Key that needs to be WATCHed to detect changes
            'retry' => 3,       // Number of retries on aborted transactions, after
            // which the client bails out with an exception.
        );

        Redis::getInstance()->transaction($options, function (Client $tx) use ($key,$account_id, $max_count, &$success) {
            $result = $tx->zrange($key,0,-1,array('WITHSCORES' => true));
            if(is_array($result)) {
                if(count($result) >= $max_count){
                    //$this->writeLog("joinRoom: accountid".$account_id." 人数已满 ".__FILE__.__LINE__);
                    $success = false;
                } else {
                    for($serial_num=1;$serial_num<=$max_count;$serial_num++){
                        if(array_search($serial_num,$result) === false){
                            $tx->multi();   // With CAS, MULTI *must* be explicitly invoked.
                            $tx->zadd($key, [$serial_num => -$account_id]);
                            $success = $serial_num;
                            break;
                        }
                    }
                }
            } else {
                //$this->writeLog("joinRoom:zrange result error ".__FILE__.__LINE__);
                $success = false;
            }
        });
        return $success;
    }

    public function deleteRoomPasswordKey($room_password){
        return Redis::getInstance(0)->hdel(RedisConst::Room_Password_Key,[$room_password]);
    }
    public function hexistsRoomPasswordKey($room_password){
        return Redis::getInstance(0)->hexists(RedisConst::Room_Password_Key,$room_password);
    }
    public function queryRoomPasswordKey($room_password){
        return Redis::getInstance(0)->hget(RedisConst::Room_Password_Key,$room_password);
    }
    public function updateRoomPasswordKey($room_password,$value){
        return Redis::getInstance(0)->hset(RedisConst::Room_Password_Key,$room_password,$value);
    }
}